package com.jintian.smart.kernel.flowable.web;

import java.io.Closeable;

import com.jintian.smart.kernel.common.context.ContextHolder;
import com.jintian.smart.kernel.common.util.StringUtil;
import com.jintian.smart.kernel.core.auth.IOperator;
import com.jintian.smart.kernel.core.auth.IOperatorProvider;
import com.jintian.smart.kernel.core.auth.IOperatorService;
import com.jintian.smart.kernel.core.flow.FlowAction;
import org.springframework.ui.ModelMap;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.WebRequestInterceptor;

/**
 * 代理拦截器，张三可以委托李四全权处理相关事务时，指定委托人。此时授权代理的模块应加载Agent-Owner的数据。
 */
public class FlowAgentWebInvokeHandler implements WebRequestInterceptor, IOperatorProvider {
    public static final String HEADER_AGENT_OWNER = "Agent-Owner";
    public static final String HEADER_DEBUGGER = "x-debug-userid";
    public static final String FLOW_OPERATOR = "flow.operator";

    private final IOperatorService operatorService;

    public FlowAgentWebInvokeHandler(IOperatorService operatorService) {
        this.operatorService = operatorService;
    }

    @Override
    public void preHandle(WebRequest request) throws Exception {
        String agentId = request.getHeader(HEADER_AGENT_OWNER);
        if (StringUtil.isNotBlank(agentId)) {
            IOperator operator = operatorService.getOperatorById(agentId);
            FlowAction.bindFlowOwner(operator);
        }
    }

    @Override
    public void postHandle(WebRequest request, ModelMap model) throws Exception {

    }

    @Override
    public void afterCompletion(WebRequest request, Exception ex) throws Exception {
        FlowAction.unbindFlowOwner();
        if (StringUtil.isNotBlank(request.getHeader(HEADER_DEBUGGER))) {
            ContextHolder.getLocalMap().remove(FLOW_OPERATOR);
        }
    }

    @Override
    public IOperator currentOperator() {
        // 1. 读取线程绑定用户
        IOperator operator = ContextHolder.get(FLOW_OPERATOR, IOperator.class);
        if (operator == null) {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes != null) {
                // debugger调用
                String debugUser = attributes.getRequest().getHeader("x-debug-userid");
                if (StringUtil.isNotBlank(debugUser)) {
                    if (operator.SUPERADMIN.getId().equals(debugUser)) {
                        operator = operator.SUPERADMIN;
                    } else {
                        operator = operatorService.getOperatorById(debugUser);
                    }
                }
            }
        }
        // 2. 读取登录用户
        if (operator == null && ContextHolder.getUserId() != null) {
            operator = operatorService.getOperatorById(ContextHolder.getUserId());
        }
        // 3. 读取流程绑定用户(兼容老代码，应使用OperatorService.administrator
        if (operator == null) {
            operator = FlowAction.getFlowOwner();
        }
        if (operator == null) {
            throw new IllegalArgumentException("无法获取操作者，请先登录系统");
        } else {
            ContextHolder.set(FLOW_OPERATOR, operator);
        }
        return operator;
    }

    public IOperator getOperator(String id) {
        return operatorService.getOperatorById(id);
    }

    @Override
    public Closeable changeOperator(String userId) {
        IOperator oldIOperator = this.currentOperator();
        IOperator newIOperator = operatorService.getOperatorById(userId);
        ContextHolder.set(FLOW_OPERATOR, newIOperator);
        return new Closeable() {
            @Override
            public void close() {
                ContextHolder.set(FLOW_OPERATOR, oldIOperator);
            }
        };
    }

    @Override
    public Closeable administrator() {
        IOperator oldIOperator = this.currentOperator();
        IOperator newIOperator = IOperator.SUPERADMIN;
        ContextHolder.set(FLOW_OPERATOR, newIOperator);
        return new Closeable() {
            @Override
            public void close() {
                ContextHolder.set(FLOW_OPERATOR, oldIOperator);
            }
        };
    }
};
